package www.com.library.view;

import android.content.Context;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.style.BackgroundColorSpan;
import android.text.style.ForegroundColorSpan;
import android.view.Gravity;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

public class UISpannableStringBuilder {
	private static final int MAX_USED_SPANS = 16;
	private Map<Integer, ForegroundColorSpan> mUsedForegroundSpan;
	private Map<Integer, BackgroundColorSpan> mUsedBackgroundSpan;
	private Map<Integer, ForegroundColorSpan> mFreeForegroundSpan;
	private Map<Integer, BackgroundColorSpan> mFreeBackgroundSpan;
	private List<UISpannableImage> mUsedImageSpan;
	private List<UISpannableImage> mFreeImageSpan;
	private String mText;
	private SpannableStringBuilder mBuilder;

	public UISpannableStringBuilder() {
		mBuilder = new SpannableStringBuilder();
		mUsedForegroundSpan = new HashMap();
		mFreeForegroundSpan = new HashMap();
		mUsedBackgroundSpan = new HashMap();
		mFreeBackgroundSpan = new HashMap();
		mUsedImageSpan = new LinkedList();
		mFreeImageSpan = new LinkedList();
		reset();
	}

	public SpannableStringBuilder getBuilder() {
		return mBuilder;
	}

	public void reset() {
		mBuilder.clear();
		mBuilder.clearSpans();

		int count = 0;
		for (Map.Entry<Integer, ForegroundColorSpan> spanEntry : mUsedForegroundSpan.entrySet()) {
			mFreeForegroundSpan.put(spanEntry.getKey(), spanEntry.getValue());
			count++;
			if (count >= MAX_USED_SPANS)
				break;
		}
		mUsedForegroundSpan.clear();

		count = 0;
		for (Map.Entry<Integer, BackgroundColorSpan> spanEntry : mUsedBackgroundSpan.entrySet()) {
			mFreeBackgroundSpan.put(spanEntry.getKey(), spanEntry.getValue());
			count++;
			if (count >= MAX_USED_SPANS)
				break;
		}
		mUsedBackgroundSpan.clear();

		count = 0;
		for (UISpannableImage imageSpan : mUsedImageSpan) {
			mFreeImageSpan.add(imageSpan);
			count++;
			if (count >= MAX_USED_SPANS)
				break;
		}
		mUsedImageSpan.clear();

		mText = "";
	}

	public String getText() {
		return mText;
	}

	public void append(String text) {
		mText += text;
		mBuilder.append(text);
	}

	public void setForegroundColorSpanString(String text, int color) {
		final int offset = mText.length();
		final int size = text.length();

		mText += text;
		mBuilder.append(text);

		ForegroundColorSpan span = mFreeForegroundSpan.get(color);
		if (span == null) {
			span = new ForegroundColorSpan(color);

			final int usedSize = mUsedForegroundSpan.size();
			final int freeSize = mFreeForegroundSpan.size();
			if (usedSize + freeSize >= MAX_USED_SPANS)
				mFreeForegroundSpan.entrySet().iterator().remove();
			mFreeForegroundSpan.put(color, span);
		}

		span = mFreeForegroundSpan.remove(color);
		if (span != null) {
			mUsedForegroundSpan.put(color, span);
			mBuilder.setSpan(span, offset, offset + size, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
		}
	}

	
	public void setBackgroundColorSpanString(String text, int color) {
		final int offset = mText.length();
		final int size = text.length();

		mText += text;
		mBuilder.append(text);

		BackgroundColorSpan span = mFreeBackgroundSpan.get(color);
		if (span == null) {
			span = new BackgroundColorSpan(color);

			final int usedSize = mUsedBackgroundSpan.size();
			final int freeSize = mFreeBackgroundSpan.size();
			if (usedSize + freeSize >= MAX_USED_SPANS)
				mFreeBackgroundSpan.entrySet().iterator().remove();
			mFreeBackgroundSpan.put(color, span);
		}

		span = mFreeBackgroundSpan.remove(color);
		if (span != null) {
			mUsedBackgroundSpan.put(color, span);
			mBuilder.setSpan(span, offset, offset + size, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
		}
	}

	public void setImage(Context ctx, int imgId) {
		final int offset = mText.length();
		final String text = " ";
		final int size = 1;

		mText += text;
		mBuilder.append(text);

		UISpannableImage span = (mFreeBackgroundSpan.size() <= 0) ? null : mFreeImageSpan.get(0);
		if (span == null) {
			span = new UISpannableImage(ctx, imgId, Gravity.CENTER_VERTICAL);
			mFreeImageSpan.add(span);
		}

		mFreeImageSpan.remove(span);
		if (span != null) {
			mUsedImageSpan.add(span);
			mBuilder.setSpan(span, offset, offset + size, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
		}
	}

	public void setSpan(Object span, int start, int end, int flags) {
		mBuilder.setSpan(span, start, end, flags);
	}
}
